const {
    emitAfterEach,
    emitBeforeEach
} = require('../utils/util.js');

async function createTask(pack) {
    try {
        await this.$checkEach(pack);
        await this.$beforeEach(pack);
        const pos = pack._target;
        if (!pos) {
            return this.$endEach(pack);
        }
        let nextAction = this.$flow.$actions.$get(pos);
        if (!nextAction) {
            return this.$endEach(pack)
        }
        nextAction.call(pack, ...pack._args);
    } catch (e) {
        console.error( 'createTask>> ', e)
        this.$throwErr(pack, e);
        return this.$endEach(pack)
    }
}
module.exports = class {
    constructor(flow) {
        this.$flow = flow;
        this.$tasks = [];
        this.$status = 'stopped';
    }
    $run(pack) {
        this.$tasks.push(createTask.bind(this, pack));
        if (this.$status == 'running') {
            return;
        }
        this.$status = 'running';
        while (this.$tasks.length) {
            this.$tasks.shift()();
        }
        this.$status = 'stopped';
    }
    $startEach(pack) {
        const tasks = [...this.$flow._onStartPlugins].map(async fn => {
            return await fn(pack);
        })
        return Promise.all(tasks)
    }
    $beforeEach(pack) {
        return emitBeforeEach(pack)
    }
    $afterEach(pack) {
        return emitAfterEach(pack)
    }
    $endEach(pack) {
        emitAfterEach(pack);
        this.$flow._onEndPlugins.forEach(fn => {
            fn(pack);
        })
        return this;
    }
    $throwErr(pack, err) {
        if (err instanceof Error) {
            err = err.message;
        }
        this.error = err;
        err && console.error(`${pack._target} error>> `, this.error);
        this.$flow._onErrorPlugins.forEach(fn => {
            fn(pack);
        })
    }
    async $checkEach(pack, type = ['validator', 'interceptor', 'link']) {
        let target = pack._target;
        let args = pack._args;
        if (this.$flow.$configs && this.$flow.$configs[target]) {
            const configs = this.$flow.$configs[target];
            if (configs.validator && type.includes('validator')) {
                let res = await configs.validator.call(pack);
                if (res instanceof Error) {
                    this.$throwErr(pack, res)
                    return new Error(target + ' validate error : ' + res.message);
                } else if (res === false) {
                    res = new Error(target + ' validate error ! ');
                    return this.$throwErr(pack, res)
                }
            }
            if (configs.interceptor && type.includes('interceptor')) {
                let res = await configs.interceptor.call(pack);
                if (res === false) return new Error(target + ' is intercepted!');
            }
        }
        return true;
    }
}
